home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 11 / Mac Magazin and MacEasy Magazine CD - Issue 11.iso / Sharewarebibliothek / Entwickler / CDEF-DeBugger 2.0 ƒ / CDEF Routines.c < prev    next >
Text File  |  1995-05-31  |  58KB  |  1,651 lines

  1. // I included some of my own drawing definitions.  Might want to check them out to understand them.
  2. // I know that my intent was to make this as simple as possible, but for me this is simple. Nothing
  3. // to complicated. Just some standard color definitions. Look at "MyColors.c" to see the functions.
  4.  
  5. // include files
  6. #include <SetUpA4.h>
  7.  
  8. // Macros & defines
  9. #define    MY_THUMB_LENGTH        32                 // simply put, this is the length of our thumb indicator.
  10.  
  11. // Prototypes
  12. static pascal long     MyControl( short variation,  ControlHandle theControl, short message, long param );
  13. void                 SetUpMyControl( CntlParam theParam );
  14. void                DrawMyControl( ControlHandle theControl, short part );
  15. short                TestMyControlParts( ControlHandle theControl, Point clickPnt );
  16. void                InitMyControl( ControlHandle theControl );
  17. void                 DisposeMyControl( ControlHandle theControl );
  18. void                FillCntlParameters( ControlHandle theControl, CntlParmPtr *param );
  19. void                CalcMyThumbPosition( ControlHandle theControl, Rect *realThumbRect );
  20. void                DrawMyArrow( short var, Rect theRect );
  21. void                DragMyThumb( ControlHandle theControl, Point mousePnt );
  22. void                DragMyControl( ControlHandle theControl, Point mousePnt );
  23. void                 DrawMyThumb( ControlHandle theControl, Boolean var );
  24. void                CalcMyThumbRgn( ControlHandle theControl, RgnHandle *param );
  25. void                PositionMyCntl( ControlHandle theControl, Point mousePnt );
  26. void                 ConvertPtToVal( ControlHandle theControl, Point newPoint, short *value );
  27. void                DrawValueInThumb( ControlHandle theControl, long value );
  28.  
  29. // globals
  30. extern Main            myMain;        // declared in Window-Main.c
  31.  
  32. /******************************************************************************
  33.  
  34.   Your code resource function starts here.
  35.   
  36.   variation        - If you have varitions of this control and they were implemented
  37.                     in you code, then if the user specifies one you will recieve it here.
  38.                     Example: Code Resource ID * 16 + varition
  39.                     
  40.   theControl    - a handle leading to the control record.
  41.   
  42.   msg            - this will be a message from the application to tell you what it
  43.                     wants. It could be drawCntl, testCntl, etc.
  44.                     
  45.   param            - this is a 4-byte value that is dependent on the msg.
  46.                     Examples of some are below in the msg's.
  47.   
  48. *******************************************************************************/
  49. static pascal long    MyControl( short variation, ControlHandle theControl, short msg, long param )
  50. {
  51.     Point            mousePnt;
  52.     Boolean            test;
  53.     
  54.     SetUpA4();
  55.     
  56.     HLock( (Handle)theControl );
  57.     if( (**theControl).contrlData ) {
  58.     
  59.         HLock( (**theControl).contrlData );
  60.         
  61.     }
  62.         
  63.     // Use 'msg' to determine what the application is wanting our control to do.
  64.     
  65.     switch( msg )
  66.     {
  67.         //------------------------------------------------------------------------------
  68.         //
  69.         //    drawCntl ( message = 0 )    IM:Macintosh ToolBox Essentials : Page 5-111
  70.         //
  71.         //     Draw the entire control or draw the part specified by LoWord( param ).
  72.         //     Be sure to check the control's hilite value. If your control has an
  73.         //     indicator or thumb and param = 129 you must erase the thumb from it's
  74.         //     current position and redraw it according to the control's new value. 
  75.         //    Do not draw anything if the control is invisible.
  76.         //
  77.         //  Return - A zero. (always)
  78.         //------------------------------------------------------------------------------
  79.         case drawCntl:
  80.             if( (**theControl).contrlVis ==  255 ) {
  81.                 DrawMyControl( theControl, LoWord( param ) );
  82.             }
  83.             return( 0L );
  84.             break;
  85.             
  86.         //------------------------------------------------------------------------------
  87.         //
  88.         //    testCntl ( message = 1 )    IM:Macintosh ToolBox Essentials : Page 5-112
  89.         //
  90.         //     Check to see if the mouse point is in the control's rect or not.
  91.         //     horizontal = LoWord( param )
  92.         //     vertical   = HiWord( param )
  93.         //    This would be the area you create your parts if you have multiple things on
  94.         //    your control. Like a thumb, arrows, pageUp, etc..
  95.         //
  96.         //    Return - The part code of the part that contains the mouse point.
  97.         //             Return zero if the mouse point is outside the part or
  98.         //             the control is inactive.
  99.         //------------------------------------------------------------------------------
  100.         case testCntl:
  101.             // first extract the mouse position
  102.             mousePnt.h = LoWord( param );
  103.             mousePnt.v = HiWord( param );
  104.             
  105.             // now determine if the mouse click was within our cntl rect.
  106.             if( PtInRect( mousePnt, &(**theControl).contrlRect )) {
  107.             
  108.                 // the click was inside our control so now define what part it was in.
  109.                 return( TestMyControlParts( theControl, mousePnt ));
  110.                 
  111.             } else {
  112.             
  113.                 // the click wasn't within our control. Don't do anything.
  114.                 return( 0L );
  115.                 
  116.             }
  117.             break;
  118.             
  119.         //------------------------------------------------------------------------------
  120.         //
  121.         //    calcCRgns ( message = 2 )    IM:Macintosh ToolBox Essentials : Page 5-112
  122.         //
  123.         //     For non System 7.x systems.  The low 3 bytes of param is a region handle.
  124.         //     ( 4 bytes for 32-bit systems ). Mask the high byte and update the region
  125.         //     to enclose the entire control. If the high bit is set then it's asking for
  126.         //  the thumb or indicator. If not just use the entire control.
  127.         //
  128.         //    Return - A zero. (always) Be sure to express the region in local coordinates.
  129.         //------------------------------------------------------------------------------
  130.         case calcCRgns:
  131.             if(( param & 0x80000000 ) == 0 ) {
  132.             
  133.                 // calculate the entire control.
  134.                 RectRgn( (RgnHandle)(param & 0x00FFFFFF), &(**theControl).contrlRect );
  135.                 
  136.             } else {
  137.                 
  138.                 // calculate only the indicator.
  139.                 Rect        realThumbRect;
  140.                 
  141.                 // obtain the current thumb position
  142.                 CalcMyThumbPosition( theControl, &realThumbRect );
  143.                 RectRgn( (RgnHandle)(param & 0x00FFFFFF), &realThumbRect );
  144.             }
  145.             return( 0L );
  146.             break;
  147.             
  148.         //------------------------------------------------------------------------------
  149.         //
  150.         //    initCntl ( message = 3 )    IM:Macintosh ToolBox Essentials : Page 5-113
  151.         //
  152.         //     Do any special inititailization, calculations or allocations here. For a
  153.         //    standard scroll bar you would normally allocate the space for a region to 
  154.         //    the control's rect and region handles for the parts and store them in the
  155.         //    'contrlData' field in the control's record.
  156.         //
  157.         //    Return - A zero. (always)
  158.         //------------------------------------------------------------------------------
  159.         case initCntl:
  160.             InitMyControl( theControl );
  161.             return( 0L );
  162.             break;
  163.             
  164.         //------------------------------------------------------------------------------
  165.         //
  166.         //    dispCntl ( message = 4 )    IM:Macintosh ToolBox Essentials : Page 5-113
  167.         //
  168.         //     Do any special disposal of your control here.
  169.         //
  170.         //    Return - A zero. (always)
  171.         //------------------------------------------------------------------------------
  172.         case dispCntl:
  173.             DisposeMyControl( theControl );
  174.             return( 0L );
  175.             break;
  176.             
  177.         //------------------------------------------------------------------------------
  178.         //
  179.         //    posCntl ( message = 5 )        IM:Macintosh ToolBox Essentials : Page 5-113
  180.         //
  181.         //     Redraw the thumb and update the control's value.
  182.         //     You use this wether you use default dragging or not.
  183.         //     horizontal = LoWord( param ) = horizontal offset in pixels to move your indicator
  184.         //     vertical   = HiWord( param ) = vertical offset in pixels to move your indicator
  185.         //
  186.         //    Return - A zero. (always)
  187.         //------------------------------------------------------------------------------
  188.         case posCntl:
  189.             // if you would like to test custom dragging comment out this function and
  190.             // un-comment the functions in 'dragCntl'. Leave return( 0L ) the same.
  191.             
  192.             mousePnt.h = LoWord( param );
  193.             mousePnt.v = HiWord( param );
  194.             PositionMyCntl( theControl, mousePnt );
  195.             
  196.             return( 0L );
  197.             break;
  198.             
  199.         //------------------------------------------------------------------------------
  200.         //
  201.         //    thumbCntl ( message = 6 )    IM:Macintosh ToolBox Essentials : Page 5-114
  202.         //
  203.         //     When you recieve this message param points to a struct which you should
  204.         //     fill with thumb motion constraints. 
  205.         //
  206.         //     struct {
  207.         //        Rect    limitRect;    // on entry, top-left is the mouse point (local coord)
  208.         //                            // on exit this should be the same as the track rects
  209.         //                            // coordinates. ( take in account the thumb width )
  210.         //        Rect    slopRect;    // if the user drags outiside this rect
  211.         //                            // the control will stop dragging.
  212.         //        short    axis;        // The axis constraints the user may drag the control.
  213.         //                            // constants than can be used are:
  214.         //                            //         noConstraint = 0; ( no constraint )
  215.         //                            //        hAxisOnly     = 1; ( drag horizontal only )
  216.         //                            //        vAxisOnly     = 2; ( drag vertical only )
  217.         //
  218.         //    * these values are ignored if you use any custom dragging
  219.         //
  220.         //    Return - Just fill in the struct.
  221.         //------------------------------------------------------------------------------
  222.         case thumbCntl:
  223.             FillCntlParameters( theControl, (CntlParmPtr*)¶m );
  224.             break;
  225.             
  226.         //------------------------------------------------------------------------------
  227.         //
  228.         //    dragCntl ( message = 7 )    IM:Macintosh ToolBox Essentials : Page 5-114
  229.         //
  230.         //    If param = 0 then drag the entire control. If param = non-zero then
  231.         //    just drag the indicator or thumb. For default dragging just return
  232.         //    a 0 (zero). For custom dragging, follow the mouse around untill released
  233.         //    then handle the details and return a non-zero.
  234.         //    NOTE: If you do return a zero then you can ignore postCntl and thumbCntl.
  235.         //
  236.         //    Return - For default dragging, return a zero. If your return something else
  237.         //             then the control manager does not drag your control. But instead
  238.         //             relies on your custom drag procedure.
  239.         //------------------------------------------------------------------------------
  240.         case dragCntl:
  241.             // if you would like to test these functions (custom dragging) remove
  242.             // the comments and comment out the functions in 'posCntl'
  243.             
  244.             //GetMouse( &mousePnt );
  245.             //DragMyThumb( theControl, param, mousePnt );
  246.             //return( 1 );
  247.             
  248.             return( 0L ); // comment out for custom dragging.
  249.             break;
  250.             
  251.         //------------------------------------------------------------------------------
  252.         //
  253.         //    autoTrack ( message = 8 )    IM:Macintosh ToolBox Essentials : Page 5-115
  254.         //
  255.         //    This message will be sent if you specify -1 in the final parameter of
  256.         //    TrackControl() and the contrlAction of the control is also -1. If so,
  257.         //    LoWord( param ) will contain a part code and a handle to a routine
  258.         //    to take care of it. Basically an action procedure as set by the user.
  259.         //------------------------------------------------------------------------------
  260.         case autoTrack:
  261.             break;
  262.                 
  263.         // The folowing messages are used only if the user is running System 7.x
  264.         // and when 32-bit addressing is enabled.
  265.         
  266.         //------------------------------------------------------------------------------
  267.         //
  268.         //    calcCntlRgn ( message = 10 )    IM:Macintosh ToolBox Essentials : Page 5-111
  269.         //
  270.         //    This is essentially the same as calcCRgns except you do not have to
  271.         //    mask out the high byte of the region handle. Used only when 32-bit
  272.         //  addressing is on and running system 7.x. If running 24-bit addressing
  273.         //    calcCRgns will still be used.
  274.         //
  275.         //    Return - A zero (always) Be sure to express the region in local coordinates.
  276.         //------------------------------------------------------------------------------
  277.         case calcCntlRgn:
  278.             RectRgn( (RgnHandle)param, &(**theControl).contrlRect );
  279.             return( 0L );
  280.             break;
  281.             
  282.         //------------------------------------------------------------------------------
  283.         //
  284.         //    calcThumbRgn ( message = 11 )    IM:Macintosh ToolBox Essentials : Page 5-111
  285.         //
  286.         //    This is asking you to calculate your indicator or thumb's region. Used
  287.         //    only when 32-bit  adressing is on and running system 7.x. If running
  288.         //    24-bit addressing calcCRgns will still be used.
  289.         //
  290.         //    Return - A zero (always) Be sure to express the region in local coordinates.
  291.         //------------------------------------------------------------------------------
  292.         case calcThumbRgn:
  293.             CalcMyThumbRgn( theControl, (RgnHandle*)¶m );
  294.             return( 0L );
  295.             break;
  296.     }
  297.     
  298.     HUnlock( (Handle)theControl );
  299.     if( (**theControl).contrlData ) {
  300.     
  301.         HUnlock( (**theControl).contrlData );
  302.         
  303.     }
  304.     
  305.     RestoreA4();
  306.     
  307. }
  308.  
  309. /******************************************************************************
  310.  
  311.     This procedure will steup you control when you are ready to allocate it.
  312.     It needs to be placed with the code up top 
  313.   
  314. *******************************************************************************/
  315. void SetUpMyControl( CntlParam theParam )
  316. {
  317.     ControlDefUPP   theControlDefUPP;
  318.     
  319.     // store the CDEF UPP in the refCon of the control, the CDEF stub gets
  320.     // the address in the refCon and calls that UPP for CDEF messages
  321.     
  322.     myMain.hControl = NewControl(     theParam.theWindow, 
  323.                                     &theParam.cntlRect, 
  324.                                     theParam.title, 
  325.                                     theParam.visible, 
  326.                                     theParam.initialValue, 
  327.                                     theParam.min, 
  328.                                     theParam.max, 
  329.                                     theParam.cntlType, 
  330.                                     (long)NewControlDefProc( MyControl ) );
  331. }
  332.  
  333. /******************************************************************************
  334.  
  335.   Draw the control. Check to see if it's active and if so, what part to draw.
  336.   Also you need to check to see if the control is horizontal or vertical and
  337.   can we draw in color.
  338.   
  339. *******************************************************************************/
  340. void    DrawMyControl( ControlHandle theControl, short part )
  341. {
  342.     Rect            cntlRect, thumbRect, arrowLT, arrowRB, trackRect;
  343.     short            cntlHilite, vCenter, hCenter;
  344.     RgnHandle        arrow;
  345.     RGBColor        theColor;
  346.     Point            mousePnt;        
  347.     MyCntlDataHan    myData;
  348.     
  349.     // retrieve the part information from the control's data field.
  350.     myData = (MyCntlDataHan)(**theControl).contrlData;
  351.     
  352.     // Did we retrieve the data?
  353.     if( myData != nil ) {
  354.     
  355.         // It worked, Alrighty then...
  356.     
  357.         // set up some variables
  358.         cntlRect     = (**theControl).contrlRect;
  359.         cntlHilite    = (**theControl).contrlHilite;
  360.         thumbRect     = (**myData).thumbRect;
  361.         arrowLT     = (**myData).arrowLT;
  362.         arrowRB     = (**myData).arrowRB;
  363.         trackRect    = (**myData).trackRect;
  364.         
  365.         // determine the centers for drawing. I haven't checked to see if I'm
  366.         // drawing a vertical or horizontal control. You will need to do this.
  367.         vCenter    = ( cntlRect.bottom - cntlRect.top ) / 2;
  368.         hCenter = ( cntlRect.right - cntlRect.left ) / 2;
  369.         
  370.  
  371.         // Determine what the hilite state of the control is
  372.         if( cntlHilite == 255 )
  373.         {
  374.             // the control is inactive. Draw accordingly
  375.             SetForeColor( GREY_C );
  376.             FrameRect( &cntlRect );
  377.             FrameRect( &arrowLT );
  378.             FrameRect( &arrowRB );
  379.             CalcMyThumbPosition( theControl, &thumbRect );
  380.             FrameRect( &thumbRect );
  381.             ColorNormal();
  382.             
  383.         } else {
  384.             
  385.             // ok, so the control is active. now what part should we draw
  386.             switch( part )
  387.             {
  388.                 //draw the entire control
  389.                 case 0:
  390.                     // ok first thing's first, let's erase the control. I'm checking to see
  391.                     // what the control's owner's (window) content color is.  Just to be nice.
  392.                     GetWinBackColor( (**theControl).contrlOwner, &theColor );
  393.                     RGBBackColor( &theColor );
  394.                     EraseRect( &cntlRect );
  395.         
  396.                     //------------------------------------------------
  397.                     // Draw left arrow
  398.                     //
  399.                     SetForeColor( GREY_B );
  400.                     PaintRect( &arrowLT );
  401.                     //--- add hilites and shadows
  402.                     HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowLT );
  403.                     FrameRect( &arrowLT );
  404.                     //--- add the black arrows. check to see if we are horz or vert
  405.                     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  406.                     
  407.                         // we are horizontal
  408.                         DrawMyArrow( 0, arrowLT );
  409.                         
  410.                     } else {
  411.                     
  412.                         // we are vertical
  413.                         DrawMyArrow( 1, arrowLT );
  414.                         
  415.                     }
  416.                     
  417.                     //------------------------------------------------
  418.                     // Draw right arrow
  419.                     //
  420.                     SetForeColor( GREY_B );
  421.                     PaintRect( &arrowRB );
  422.                     //--- add hilites and shadows
  423.                     HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowRB );
  424.                     FrameRect( &arrowRB );
  425.                     //--- add the black arrows. check to see if we are horz or vert
  426.                     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  427.                     
  428.                         // we are horizontal
  429.                         DrawMyArrow( 2, arrowRB );
  430.                         
  431.                     } else {
  432.                         
  433.                         // we are vertical
  434.                         DrawMyArrow( 3, arrowRB );
  435.                         
  436.                     }
  437.                     
  438.                     
  439.                     //------------------------------------------------
  440.                     // Draw the track part and the thumb. We put these
  441.                     // together because we might have to erase an old thumb position.
  442.                     //
  443.                     DrawMyThumb( theControl, 0 );
  444.                     break;
  445.                     
  446.                     
  447.                     
  448.                 case 20: // inUpButton
  449.                     //------------------------------------------------
  450.                     //     Let's erase the arrow's rect. Agin I'm getting the content color
  451.                     //    of the controls owner. (the window we're in)
  452.                     //
  453.                     GetWinBackColor( (**theControl).contrlOwner, &theColor );
  454.                     RGBBackColor( &theColor );
  455.                     EraseRect( &arrowLT );
  456.                     
  457.                     GetMouse( &mousePnt );
  458.                     if( PtInRect( mousePnt, &arrowLT ) && Button()) {
  459.                     
  460.                         //------------------------------------------------
  461.                         // Draw left arrow - inverted
  462.                         //
  463.                         SetForeColor( GREY_E );
  464.                         PaintRect( &arrowLT );
  465.                         //--- add hilites and shadows
  466.                         HiliteAndShadow( GREY_H, GREY_B, 0, arrowLT );
  467.                         FrameRect( &arrowLT );
  468.                         //--- add the arrows. check to see if we are horz or vert
  469.                         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  470.                         
  471.                             // we are horizontal
  472.                             DrawMyArrow( 0, arrowLT );
  473.                             
  474.                         } else {
  475.                         
  476.                             // we are vertical
  477.                             DrawMyArrow( 1, arrowLT );
  478.                             
  479.                         }
  480.                         
  481.                     } else {
  482.                     
  483.                         //------------------------------------------------
  484.                         // Draw left arrow - normal
  485.                         //
  486.                         SetForeColor( GREY_B );
  487.                         PaintRect( &arrowLT );
  488.                         //--- add hilites and shadows
  489.                         HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowLT );
  490.                         FrameRect( &arrowLT );
  491.                         //--- add the arrows. check to see if we are horz or vert
  492.                         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  493.                         
  494.                             // we are horizontal
  495.                             DrawMyArrow( 0, arrowLT );
  496.                             
  497.                         } else {
  498.                         
  499.                             // we are vertical
  500.                             DrawMyArrow( 1, arrowLT );
  501.                             
  502.                         }
  503.                     
  504.                     }
  505.                     ColorNormal();
  506.                     break;
  507.                     
  508.                     
  509.                     
  510.                     
  511.                 case 21: //inDownButton
  512.                     //------------------------------------------------
  513.                     //     Let's erase the arrow's rect. Again I'm getting the content color
  514.                     //    of the controls owner. (the window we're in)
  515.                     //
  516.                     GetWinBackColor( (**theControl).contrlOwner, &theColor );
  517.                     RGBBackColor( &theColor );
  518.                     EraseRect( &arrowRB );
  519.                     
  520.                     //________________________________________________
  521.                     //    We need to determine how we should draw the arrows. Is the user
  522.                     //    clicking on them or is it normal? If it is being clicked on then
  523.                     //    we should check where the mouse is and if the button is down. This
  524.                     //    will determine if we draw the control inverted or not.
  525.                     //
  526.                     GetMouse( &mousePnt );
  527.                     if( PtInRect( mousePnt, &arrowRB ) && Button()) {
  528.                     
  529.                         //------------------------------------------------
  530.                         // Draw right arrow - inverted
  531.                         //
  532.                         SetForeColor( GREY_E );
  533.                         PaintRect( &arrowRB );
  534.                         //--- add hilites and shadows
  535.                         HiliteAndShadow( GREY_H, GREY_B, 0, arrowRB );
  536.                         FrameRect( &arrowRB );
  537.                         //--- add the black arrows. check to see if we are horz or vert
  538.                         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  539.                         
  540.                             // we are horizontal
  541.                             DrawMyArrow( 2, arrowRB );
  542.                             
  543.                         } else {
  544.                             
  545.                             // we are vertical
  546.                             DrawMyArrow( 3, arrowRB );
  547.                             
  548.                         }
  549.                     
  550.                     } else {
  551.                         
  552.                         //------------------------------------------------
  553.                         // Draw right arrow - normal
  554.                         //
  555.                         SetForeColor( GREY_B );
  556.                         PaintRect( &arrowRB );
  557.                         //--- add hilites and shadows
  558.                         HiliteAndShadow( WHITE_COLOR, GREY_E, 0, arrowRB );
  559.                         FrameRect( &arrowRB );
  560.                         //--- add the black arrows. check to see if we are horz or vert
  561.                         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  562.                         
  563.                             // we are horizontal
  564.                             DrawMyArrow( 2, arrowRB );
  565.                             
  566.                         } else {
  567.                             
  568.                             // we are vertical
  569.                             DrawMyArrow( 3, arrowRB );
  570.                             
  571.                         }
  572.                         
  573.                     }
  574.                     ColorNormal();
  575.                     break;
  576.                     
  577.                 
  578.                 
  579.                 case 22: // inPageUp
  580.                 case 23: // inPageDown
  581.                     //------------------------------------------------
  582.                     // All we need to do here is determine if we are to the left or right
  583.                     // ( or top or bottom ) of the thumb's position.  Then create a rect
  584.                     // who's left or right ( top or bottom ) is that of the thumb's.
  585.                     //
  586.                     
  587.                     // get the current mouse position
  588.                     GetMouse( &mousePnt );
  589.                     
  590.                     // need to find if we are a vert or horz control. Only need to do this when
  591.                     // we are inverting the control. We need to draw the entire control when
  592.                     // asked to draw it normally. Why?!? Because when we invert it we create
  593.                     // Hilites and shadows which need to be erased.
  594.                     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  595.                     
  596.                         // we are horizontal
  597.                         
  598.                         // find out where our current thumb is located ( real corrdinates )
  599.                         CalcMyThumbPosition( theControl, &thumbRect );
  600.                         
  601.                         // where is the mouse? on the right or the left?
  602.                         if( mousePnt.h <= thumbRect.left ) {
  603.                             trackRect.right = thumbRect.left;
  604.                         } else {
  605.                             trackRect.left = thumbRect.right - 1;
  606.                         }
  607.                         
  608.                     } else {
  609.                         
  610.                         // we are a vertical control
  611.                         
  612.                         // find out where our current thumb is located ( real corrdinates )
  613.                         CalcMyThumbPosition( theControl, &thumbRect );
  614.                         
  615.                         // where is the mouse? on the top or the bottom?
  616.                         if( mousePnt.v <= thumbRect.top ) {
  617.                             trackRect.bottom = thumbRect.top + 1;
  618.                         } else {
  619.                             trackRect.top = thumbRect.bottom - 1;
  620.                         }
  621.                     }
  622.                         
  623.                     // now figure out how to draw it. ( inverted or normal )
  624.                     // and check to see if the are in the track portion or not.
  625.                     if( PtInRect( mousePnt, &trackRect ) && Button()) {
  626.                     
  627.                         //------------------------------------------------
  628.                         // Draw the trackRect part ( not the thumb ) - inverted
  629.                         //
  630.                         InvertRect( &trackRect );
  631.                         SetForeColor( GREY_C );
  632.                         PaintRect( &trackRect );
  633.                         //--- add hilites and shadows
  634.                         HiliteAndShadow( GREY_G, WHITE_COLOR, 0, trackRect );
  635.                         FrameRect( &trackRect );
  636.                         
  637.                     } else {
  638.                     
  639.                         //------------------------------------------------
  640.                         // Draw the track part ( not the thumb ) - normal
  641.                         //
  642.                         SetForeColor( GREY_A );
  643.                         PaintRect( &trackRect );
  644.                         //--- add hilites and shadows
  645.                         HiliteAndShadow( GREY_C, WHITE_COLOR, 0, trackRect );
  646.                         FrameRect( &trackRect );
  647.                         
  648.                         CalcMyThumbPosition( theControl, &thumbRect );
  649.                         SetForeColor( GREY_B );
  650.                         PaintRect( &thumbRect );
  651.                         //--- add hilites and shadows
  652.                         HiliteAndShadow( WHITE_COLOR, GREY_E, 0, thumbRect );
  653.                         FrameRect( &thumbRect );
  654.                         
  655.                     }
  656.                     break;
  657.                     
  658.                 
  659.                 case 129: // inThumb
  660.                     // We don't have to do this here. Actually i don't believe it
  661.                     // will even get called here. This has it's own routine I believe.
  662.                     break;
  663.                     
  664.             }
  665.             
  666.         }
  667.     } else {
  668.     
  669.         // we had some problem retrieving our data
  670.         ReportError( "\pCouldn't retrieve data for drawing the control." );
  671.         
  672.     }
  673. }
  674.  
  675. /******************************************************************************
  676.  
  677.   Test to see what part the user clicked in. We already checked to see if the
  678.   mouse click was actually inside the control. It was, so now see what part
  679.   they clicked in and return a number for it. Apple has a set of variables that
  680.   is uses for standard controls. So since our control is a variation of a normal
  681.   slider we'll use their variables. Check out FindControl() in IM or THINK Ref.
  682.   
  683. *******************************************************************************/
  684. short    TestMyControlParts( ControlHandle theControl, Point clickPnt )
  685. {
  686.     Rect            pageLeft, pageRight, realThumbRect, cntlRect;
  687.     MyCntlDataHan    myData;
  688.     
  689.     //    For our own refrence let's define our parts..
  690.     //
  691.     //    thumb        = inThumb         = 129
  692.     //    arrowLT     = inUpButton     = 20
  693.     //     arrowRB     = inDownButton    = 21
  694.     //    pageLeft    = inPageUp        = 22
  695.     //    pageRight    = inPageDown    = 23
  696.     
  697.     // ok let's get our stored data from the control's contrlData field
  698.     myData        = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
  699.     
  700.     // set up the control's rectangle for testing
  701.     cntlRect = (**theControl).contrlRect;
  702.     
  703.     // we need to find out what the real thhumb on the control's rect is
  704.     CalcMyThumbPosition( theControl, &realThumbRect );
  705.     
  706.     // double check to make sure that in fact we have data to play with
  707.     if( myData != nil ) {
  708.         
  709.         // it worked. wow!
  710.         // now, all we do is test where exactly in the control the click was.
  711.         
  712.         //is it in the thumb?
  713.         if( PtInRect( clickPnt, &realThumbRect ) ) {
  714.             return( inThumb );
  715.         } else {
  716.         
  717.             // is it in one of the arrows?
  718.             if( PtInRect( clickPnt, &(**myData).arrowLT ) ) {
  719.                 return( inUpButton );
  720.             } else {
  721.             
  722.                 if( PtInRect( clickPnt, &(**myData).arrowRB ) ) {
  723.                     return( inDownButton );
  724.                 } else {
  725.                 
  726.                     // is it in the trackRect somewhere?
  727.                     if( PtInRect( clickPnt, &(**myData).trackRect ) ) {
  728.                         
  729.                         // we have to see if it's to the right of the thumb or left of it. Or if we are
  730.                         // a vertical control the top and the bottom.
  731.                         
  732.                         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  733.                         
  734.                             // we have a horizontal control
  735.                             
  736.                             pageLeft = pageRight = (**myData).trackRect;
  737.                             pageLeft.right = realThumbRect.left;
  738.                             pageRight.left = realThumbRect.right;
  739.                             
  740.                         } else {
  741.                         
  742.                             // we have a vertical control
  743.                             
  744.                             pageLeft = pageRight = (**myData).trackRect;
  745.                             pageLeft.bottom = realThumbRect.top;
  746.                             pageRight.top = realThumbRect.bottom;
  747.                             
  748.                         }
  749.                         
  750.                         if( PtInRect( clickPnt, &pageLeft ) ) {
  751.                             return( inPageUp );
  752.                         } else {
  753.                             if( PtInRect( clickPnt, &pageRight ) ) {
  754.                                 return( inPageDown );
  755.                             }
  756.                         }
  757.                         
  758.                     } else {
  759.                     
  760.                         // hey it wasn't in any of my rects. how'd that happ'n?
  761.                         ReportError( "\pTesting points and couldn't find point within any of my parts." );
  762.                     }
  763.                 }
  764.             }
  765.         }
  766.         
  767.     } else {
  768.         
  769.         // retrieving the control's data failed.
  770.         ReportError( "\pCouldn't retrieve control data while testing the control." );
  771.         
  772.     }
  773.     
  774. }
  775.  
  776. /******************************************************************************
  777.     
  778.     When we recieve a 'initCntl' message in our control we use this procedure
  779.     to set up the 'contrlData' field in our control.  This data is used to
  780.     store information about our control that we will use throughout it's life.
  781.     
  782. *******************************************************************************/
  783. void    InitMyControl( ControlHandle theControl )
  784. {
  785.     Rect            cntlRect, thumbRect, arrowLT, arrowRB, trackRect, slopRect;
  786.     short            cntl_high = 0, cntl_wide = 0;
  787.     MyCntlDataHan    myData;
  788.     
  789.     // set our cntlRect to equal the control's rect.
  790.     cntlRect = (**theControl).contrlRect;
  791.     
  792.     // we need to determine if we have a vertical or horizontal control
  793.     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  794.         
  795.         // we have a horizontal control
  796.         
  797.         // the first thing to do is determine the height of our control to make square arrows buttons
  798.         cntl_high = cntlRect.bottom - cntlRect.top;
  799.         
  800.         // first we'll set the arrow buttons.
  801.         SetRect( &arrowLT, cntlRect.left, cntlRect.top, cntlRect.left + cntl_high, cntlRect.bottom );
  802.         SetRect( &arrowRB, cntlRect.right - cntl_high, cntlRect.top, cntlRect.right, cntlRect.bottom );
  803.         
  804.         // Now we'll set the track's rectangle. Take the cntlRect - the arrow buttons.
  805.         trackRect = cntlRect;
  806.         trackRect.left = arrowLT.right - 1; // we want them to overlap.
  807.         trackRect.right = arrowRB.left + 1; // we want them to overlap.
  808.         
  809.         // Now we'll set the thumb rect up. We don't have to actually set the rect
  810.         // to it's exact position, but just the size for now.
  811.         //    Right = width
  812.         //  Bottom = height (cntlRect's height - 2, so it's inset little.)
  813.         SetRect( &thumbRect, 0, 0, MY_THUMB_LENGTH, cntl_high - 2 );
  814.         
  815.     } else {
  816.     
  817.         // we have a vertical control
  818.         
  819.         // the first thing to do is determine the width of our control to make square arrows buttons
  820.         cntl_wide = cntlRect.right - cntlRect.left;
  821.         
  822.         // first we'll set the arrow buttons.
  823.         SetRect( &arrowLT, cntlRect.left, cntlRect.top, cntlRect.right, cntlRect.top + cntl_wide );
  824.         SetRect( &arrowRB, cntlRect.left, cntlRect.bottom - cntl_wide, cntlRect.right, cntlRect.bottom );
  825.         
  826.         // Now we'll set the track's rectangle. Take the cntlRect - the arrow buttons.
  827.         trackRect = cntlRect;
  828.         trackRect.top = arrowLT.bottom - 1;
  829.         trackRect.bottom = arrowRB.top + 1;
  830.         
  831.         // Now we'll set the thumb rect up. We don't have to actually set the rect
  832.         // to it's exact position, but just the size for now.
  833.         //    Right = height (cntlRect's height - 2, so it's inset little.)
  834.         //  Bottom = width
  835.         SetRect( &thumbRect, 0, 0, cntl_wide - 2, MY_THUMB_LENGTH );
  836.     }
  837.     
  838.     // we need to set the size of the handle we are using
  839.     myData = (MyCntlDataHan)NewHandle( sizeof( MyCntlData ) );
  840.     
  841.     if( myData != nil ) {
  842.         
  843.         // now store our handle in the contrlData field in the control record
  844.         (**theControl).contrlData  = (Handle)myData;
  845.         
  846.         // now simply copy this information into our handle.
  847.         (**myData).cntlRect        = cntlRect;
  848.         (**myData).thumbRect    = thumbRect;
  849.         (**myData).arrowLT        = arrowLT;     // left or top arrow
  850.         (**myData).arrowRB        = arrowRB;    // right or bottom arrow
  851.         (**myData).trackRect    = trackRect;
  852.         
  853.     } else {
  854.     
  855.         // We had any error. Respond what error had occured.
  856.         ReportError( "\pCouldn't allocate area for the data handle." );
  857.         
  858.     }
  859.         
  860. }
  861.  
  862. /******************************************************************************
  863.     
  864.     This procedure will get called when we recieve a 'dispCntl' in the
  865.     param of our control.  All we need to do is distroy any data that we
  866.     initialized earlier in the 'initCntl' procedure.
  867.     
  868. *******************************************************************************/
  869. void     DisposeMyControl( ControlHandle theControl )
  870. {
  871.     MyCntlDataHan    myData;
  872.     
  873.     if( theControl != nil ) {
  874.     
  875.         // Get the handle to the control's data.
  876.         myData = (MyCntlDataHan)(**theControl).contrlData;
  877.         
  878.         if( myData != nil ) {
  879.         
  880.             // lock the structs data.
  881.             HLock( (Handle) myData );
  882.             
  883.             // dispose of our data handle and set the contrlData field to nil.
  884.             DisposeHandle(     (Handle) myData );
  885.             (**theControl).contrlData = nil;
  886.             
  887.         } else {
  888.             
  889.             // error occurred trying to retreive info from the control's data field.
  890.             ReportError( "\pCouldn't retrieve control data information." );
  891.             
  892.         }
  893.     } else {
  894.     
  895.         // For some reason we didn't get a true control handle passed to us
  896.         ReportError( "\pTried to extract data information, but was passed a bad control handle." );
  897.     
  898.     }
  899. }
  900.  
  901. /******************************************************************************
  902.  
  903.     Out Control recieved a 'thumbCntl' message. We need to fill in the parameters
  904.     of the controls limit rect and slop rect and axis.
  905.     
  906.       By the way, CntlParm is a struct defined on top. We use it here to set up
  907.       or force the data that lies within 'param' to match our requirements. 
  908.   
  909. *******************************************************************************/
  910. void    FillCntlParameters( ControlHandle theControl, CntlParmPtr *param )
  911. {
  912.     Rect            limitRect, slopRect, cntlRect, realThumbRect;
  913.     short            axis;
  914.     Point            mousePnt;
  915.     MyCntlDataHan    myData;
  916.     
  917.     // You may be asking yourself, "What exactly are we doing here?"
  918.     // Well we are setting some parameters, that Apple has provided
  919.     // us control definition makers, to allow some helpful human
  920.     // interaction. ( At least I think so ).
  921.     //
  922.     // The limitRect gives us the mouse coordinates on entry. On exit 
  923.     // this rect should contain the control track rectangle. The slopRect
  924.     // gives us an area in which the user can drag outside the control's
  925.     // rectangle in which the control will still respond. If the user moves
  926.     // outside this 'slop rectangle' then the control will return to it's
  927.     // previous state. The axis constrain the drag movement depending on the
  928.     // setting. noContraint = 0 ( no constraint ), hAxisOnly = 1 ( horizontal only ),
  929.     // vAxisOnly = 2 ( vertical only ).
  930.     
  931.     // extract data from the contrlData field and form to our struct.
  932.     myData        = (MyCntlDataHan)(**theControl).contrlData; 
  933.     
  934.     // let's get the true or real thumb rect ( the one that gets drawn )
  935.     CalcMyThumbPosition( theControl, &realThumbRect );
  936.     
  937.     // set the cntlRect to match the control's rectangle
  938.     cntlRect = (**theControl).contrlRect;
  939.     
  940.     // extract the mouse down points from param
  941.     mousePnt.h = (**param).limitRect.left;
  942.     mousePnt.v = (**param).limitRect.top;
  943.     
  944.     if( myData != nil ) {
  945.     
  946.         // now let's determine if we are using a horz or vert control
  947.         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  948.         
  949.             // we have ourselves a horizontal control
  950.             
  951.             // adjust the limitRect to take in account where the user clicked whithin the thumb
  952.             (**param).limitRect.left = (**myData).arrowLT.right + ( mousePnt.h - realThumbRect.left );
  953.             (**param).limitRect.right = (**myData).arrowRB.left - ( (realThumbRect.right-1) - mousePnt.h );
  954.             
  955.             // now let's adjust the slopRect slightly, increase it by 20 pixels...
  956.             (**param).slopRect = (**myData).trackRect;
  957.             InsetRect( &(**param).slopRect, -20, -20 );
  958.             
  959.             // then extend it's edges about 100 pixels. This normally gives the correct feel.
  960.             (**param).slopRect.left -= 100;
  961.             (**param).slopRect.right += 100;
  962.             
  963.             // set up the axis for a horizontal control
  964.             (**param).axis = hAxisOnly;
  965.         
  966.         } else {
  967.         
  968.             // we have a vertical control.
  969.             
  970.             // adjust the limitRect to take in account where the user clicked whithin the thumb
  971.             (**param).limitRect.top = (**myData).arrowLT.bottom + ( mousePnt.v - realThumbRect.top );
  972.             (**param).limitRect.bottom = (**myData).arrowRB.top - ( (realThumbRect.bottom-1) - mousePnt.v );
  973.             
  974.             // now let's adjust the slopRect slightly, increase it by 20 pixels...
  975.             (**param).slopRect = (**myData).trackRect;
  976.             InsetRect( &(**param).slopRect, -20, -20 );
  977.             
  978.             // then extend it's edges about 100 pixels. This normally gives the correct feel.
  979.             slopRect.top -= 100;
  980.             slopRect.bottom += 100;
  981.             
  982.             // set up the axis for the control
  983.             (**param).axis = vAxisOnly;
  984.             
  985.         }
  986.         
  987.     } else {
  988.     
  989.         // we had an error retreiving data form the control
  990.         ReportError( "\pWe couldn't extract data from the control while calculating the parameters." );
  991.             
  992.     }
  993. }
  994.  
  995. /******************************************************************************
  996.  
  997.   This is a fairly straight forward procedure. All we have to do is find the position of
  998.   the thumb on the track and return a rect to match these values. Easy shmeazy. All
  999.   we are doing here is calculating the "Real Thumb Rect" for drawing.
  1000.   
  1001. *******************************************************************************/
  1002. void    CalcMyThumbPosition( ControlHandle theControl, Rect *realThumbRect )
  1003. {
  1004.     long            min, max, value, dist;
  1005.     short            cntl_high, cntl_wide;
  1006.     Rect            cntlRect, trackRect;
  1007.     MyCntlDataHan    myData;
  1008.     
  1009.     // Do some initial setting up
  1010.     cntlRect    = (**theControl).contrlRect;
  1011.     min             = (**theControl).contrlMin;
  1012.     max             = (**theControl).contrlMax;
  1013.     value        = (**theControl).contrlValue;
  1014.     myData        = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
  1015.     
  1016.     // double check to make sure that in fact we have data to play with
  1017.     if( myData != nil ) {
  1018.         
  1019.         // it worked! cool...
  1020.         
  1021.         // make sure the value isn't greater or less than max & min
  1022.         if( value > max ) {
  1023.             value = max;
  1024.         } else {
  1025.             if( value < min ) {
  1026.                 value = min;
  1027.             }
  1028.         }
  1029.         
  1030.         // retrieve the track rect from our data
  1031.         trackRect = (**myData).trackRect;
  1032.         
  1033.         // Do we have a horizontal or vertical control???
  1034.         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top )
  1035.         {
  1036.             // We have horizontal control
  1037.             
  1038.             // We need to set the trackRect to take in account of the thumb width.
  1039.             // We do this so we don't overwrite part of the arrow when we are drawing.
  1040.             trackRect.left  += ( MY_THUMB_LENGTH / 2 ) + 1;
  1041.             trackRect.right -= ( MY_THUMB_LENGTH / 2 ) + 1;
  1042.             
  1043.             // determine how wide our track rect is and then calculate the distance we move.
  1044.             cntl_wide = trackRect.right - trackRect.left;
  1045.             dist = trackRect.left + (((max + value) * cntl_wide) / (max - min)) - ( MY_THUMB_LENGTH / 2 );
  1046.             
  1047.             // we know that the top and bottom of our thumb rect will be the same as the
  1048.             // control's rect (basically). It's actually inset 1 pixel to fit inside the track.
  1049.             (*realThumbRect).top     = cntlRect.top + 1;
  1050.             (*realThumbRect).bottom = cntlRect.bottom - 1;
  1051.             
  1052.             // now set the left and right to the correct coordinates for drawing.
  1053.             (*realThumbRect).left  = (**myData).thumbRect.left + dist;
  1054.             (*realThumbRect).right = (**myData).thumbRect.right + dist;
  1055.             
  1056.         } else {
  1057.             
  1058.             // We have a vertical control
  1059.             
  1060.             // We need to set the trackRect to take in account of the thumb width.
  1061.             // We do this so we don't overwrite part of the arrow when we are drawing.
  1062.             trackRect.top       += ( MY_THUMB_LENGTH / 2 ) + 1;
  1063.             trackRect.bottom -= ( MY_THUMB_LENGTH / 2 ) + 1;
  1064.             
  1065.             // determine how tall our track rect is and then calculate the distance we move.
  1066.             cntl_high = trackRect.bottom - trackRect.top;
  1067.             dist = trackRect.top + (((max + value) * cntl_high) / (max - min)) - ( MY_THUMB_LENGTH / 2 );
  1068.             
  1069.             // we know that the left and right of our thumb rect will be the same as the
  1070.             // control's rect (basically). It's actually inset 1 pixel to fit inside the track.
  1071.             (*realThumbRect).left  = cntlRect.left + 1;
  1072.             (*realThumbRect).right = cntlRect.right - 1;
  1073.             
  1074.             // now set the top and bottom to the correct coordinates for drawing.
  1075.             (*realThumbRect).top     = (**myData).thumbRect.top + dist;
  1076.             (*realThumbRect).bottom = (**myData).thumbRect.bottom + dist;
  1077.             
  1078.         }
  1079.     } else {
  1080.     
  1081.         // we had a problem getting our data. bummer!
  1082.         ReportError( "\pTrying to calculate thumb postion and couldn't access data field." );
  1083.         
  1084.     }
  1085. }
  1086.  
  1087. /******************************************************************************
  1088.  
  1089.   This procedure will draw the black arrows located in my arrow buttons.
  1090.   you pass it a variable that tells which way the arrow should point and a
  1091.   rect in which the arrow will be drawn. Fairly straight forward.
  1092.   
  1093.   0 = points left
  1094.   1 = points up
  1095.   2 = points right
  1096.   3 = points down
  1097.   
  1098. *******************************************************************************/
  1099. void    DrawMyArrow( short var, Rect theRect )
  1100. {
  1101.     RgnHandle        arrow;
  1102.     short            center;
  1103.     
  1104.     arrow = NewRgn();
  1105.     OpenRgn();
  1106.     
  1107.     switch( var ) {
  1108.         
  1109.         case 0:  // points left
  1110.             center = ( theRect.bottom - theRect.top ) / 2;
  1111.             MoveTo( theRect.left + 5, theRect.top + center );
  1112.             LineTo( theRect.right - 6, theRect.top + 2 );
  1113.             LineTo( theRect.right - 6, theRect.bottom - 4 );
  1114.             LineTo( theRect.left + 5, theRect.bottom - center );
  1115.             break;
  1116.             
  1117.         case 1:  // points up
  1118.             center = ( theRect.right - theRect.left ) / 2;
  1119.             MoveTo( theRect.left + 1, theRect.bottom - 6 );
  1120.             LineTo( theRect.left + center - 1, theRect.top + 5 );
  1121.             LineTo( theRect.right - 3, theRect.bottom - 6 );
  1122.             LineTo( theRect.left + 1, theRect.bottom - 6 );
  1123.             break;
  1124.             
  1125.         case 2:  // points right
  1126.             center = ( theRect.bottom - theRect.top ) / 2;
  1127.             MoveTo( theRect.right - 5, theRect.top + center + 1 );
  1128.             LineTo( theRect.left + 6, theRect.top + 3 );
  1129.             LineTo( theRect.left + 6, theRect.bottom - 4 );
  1130.             LineTo( theRect.right - 5, theRect.bottom - center - 1 );
  1131.             break;
  1132.             
  1133.         case 3:  // points down
  1134.             center = ( theRect.right - theRect.left ) / 2;
  1135.             MoveTo( theRect.left + 2, theRect.top + 6 );
  1136.             LineTo( theRect.left + center, theRect.bottom - 5 );
  1137.             LineTo( theRect.right - 4, theRect.top + 6 );
  1138.             LineTo( theRect.left + 2, theRect.top + 6 );
  1139.             break;
  1140.     
  1141.     }
  1142.     
  1143.     CloseRgn( arrow );
  1144.     FillRgn( arrow, &black );
  1145.     DisposeRgn( arrow );
  1146. }
  1147.  
  1148. /******************************************************************************
  1149.  
  1150.     Custom Dragging Procedure - not needed if you use default dragging. 
  1151.                                 ( when TrackControl is passed a zero for
  1152.                                   the tracking procedure )
  1153.     
  1154.     Used to move the indicator or thumb.
  1155.                                   
  1156.     This procedure will show the user the interaction when they click on the
  1157.     thumb part of our control.  All we are going to do is drag the thumb's
  1158.     rect around using the drag grey rgn routine untill the user let's up on the
  1159.     mouse. For kicks and grins we will also draw the control's value above the
  1160.     indicator. We also will use the parameters that we set for slop rect and limit rect.
  1161.     
  1162. *******************************************************************************/
  1163. void    DragMyThumb( ControlHandle theControl, Point mousePnt )
  1164. {
  1165.     RgnHandle        thumbRgn;
  1166.     Rect            slopRect, limitRect, realThumbRect, cntlRect;
  1167.     long            newPoint;
  1168.     MyCntlDataHan    myData;
  1169.     short            value, axis;
  1170.     
  1171.     // set up some variables..
  1172.     myData        = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
  1173.     cntlRect    = (**theControl).contrlRect;
  1174.     
  1175.     // double check to make sure that in fact we have data to play with
  1176.     if( myData != nil ) {
  1177.     
  1178.         // it worked, hurray.
  1179.         
  1180.         // let's get the true or real thumb rect ( the one that gets drawn )
  1181.         CalcMyThumbPosition( theControl, &realThumbRect );
  1182.         
  1183.         // this is where we are declaring the parameters for dragging.
  1184.         slopRect = limitRect = (**myData).trackRect;
  1185.         
  1186.         // now let's determine if we are using a horz or vert control
  1187.         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  1188.         
  1189.             // we have ourselves a horizontal control
  1190.             
  1191.             // adjust the limitRect to take in account where the user clicked whithin the thumb
  1192.             limitRect.left = (**myData).arrowLT.right + ( mousePnt.h - realThumbRect.left );
  1193.             limitRect.right = (**myData).arrowRB.left - ( (realThumbRect.right-1) - mousePnt.h );
  1194.             
  1195.             // now let's adjust the slopRect slightly, increase it by 20 pixels...
  1196.             InsetRect( &slopRect, -20, -20 );
  1197.             
  1198.             // then extend it's edges about 100 pixels. This normally gives the correct feel.
  1199.             slopRect.left -= 100;
  1200.             slopRect.right += 100;
  1201.             
  1202.             // define our axis that we will use to constrain the indicators movement.
  1203.             axis = hAxisOnly;
  1204.         
  1205.         } else {
  1206.         
  1207.             // we have a vertical control.
  1208.             
  1209.             // adjust the limitRect to take in account where the user clicked whithin the thumb
  1210.             limitRect.top = (**myData).arrowLT.bottom + ( mousePnt.v - realThumbRect.top );
  1211.             limitRect.bottom = (**myData).arrowRB.top - ( (realThumbRect.bottom-1) - mousePnt.v );
  1212.             
  1213.             // now let's adjust the slopRect slightly, increase it by 20 pixels...
  1214.             InsetRect( &slopRect, -20, -20 );
  1215.             
  1216.             // then extend it's edges about 100 pixels. This normally gives the correct feel.
  1217.             slopRect.top -= 100;
  1218.             slopRect.bottom += 100;
  1219.             
  1220.             // define our axis that we will use to constrain the indicators movement.
  1221.             axis = vAxisOnly;
  1222.             
  1223.         }
  1224.         
  1225.         // we've been asked to only move the indicator
  1226.     
  1227.         // now do our dragging. first declare a new rgn to copy out thumb rect into.
  1228.         // then this gets passed to the DragGrayRgn() procedure.  It actually handles the dragging.
  1229.         thumbRgn = NewRgn();
  1230.         RectRgn( thumbRgn, &realThumbRect );
  1231.         
  1232.         // This is the actual routine to drag the indicator. For a more detailed explanation
  1233.         // look on page 4-96 in IM:Toolbox Essentails or use Think Refrence.
  1234.         newPoint = DragGrayRgn( thumbRgn, mousePnt, &limitRect, &slopRect, axis, nil );
  1235.         
  1236.         // now determine if the thumb did in fact move. if DragGrayRgn() returns a value of
  1237.         // 0x80008000 it means that the user realeased the mouse outside the sloprect. HiWord
  1238.         // of newPoint is the vertical dist moved where as the LoWord is horz dist moved.
  1239.         
  1240.         if( newPoint != 0x80008000 ) {
  1241.             
  1242.             // It was released inside our control. newPoint will contain the horizontal and vertical 
  1243.             // ditance moved.
  1244.             
  1245.             mousePnt.h = LoWord( newPoint );
  1246.             mousePnt.v = HiWord( newPoint );
  1247.             ConvertPtToVal( theControl, mousePnt, &value );
  1248.             SetCtlValue( theControl, value );
  1249.             DrawMyThumb( theControl, 1 );
  1250.             DrawValueInThumb( theControl, value );
  1251.             
  1252.         } else {
  1253.         
  1254.             // it was released outside the slopRect. Do nothing
  1255.             ReportError( "\pYou released the mouse outside the slop Rect." );
  1256.             
  1257.         }
  1258.         
  1259.         DisposeRgn( thumbRgn );
  1260.         
  1261.     } else {
  1262.     
  1263.         // it didn't work
  1264.         ReportError( "\pCouldn't retrieve control data while dragging the control's thumb." );
  1265.         
  1266.     }
  1267. }
  1268.  
  1269. /******************************************************************************
  1270.  
  1271.     Custom Dragging Procedure - not needed if you use default dragging. 
  1272.                                 ( when TrackControl is passed a zero for
  1273.                                   the tracking procedure )
  1274.     
  1275.     Used to move the entire control.
  1276.                                   
  1277.     This procedure is only used when the user is given the ability to move
  1278.     the entire control. I really haven't thought of any reason to do this, but
  1279.     if it's something that is implicated in your code then here it is.
  1280.     
  1281.     limitRect - will most likely be the control's ownern's content region.
  1282.     slopRect  - will be whatever value you think should be used. for tutorial
  1283.                 purposes I'll use the window's content region inset -20
  1284.     axis      - I'll assume that you would want to give them complete freedom.
  1285.                 No constraint.
  1286.     
  1287. *******************************************************************************/
  1288. void    DragMyControl( ControlHandle theControl, Point mousePnt )
  1289. {
  1290.     Rect            slopRect, limitRect, cntlRect;
  1291.     short            axis;
  1292.     WindowPtr        cntlWindow;
  1293.     
  1294.     // set up some variables..
  1295.     cntlRect    = (**theControl).contrlRect;
  1296.     cntlWindow  = (**theControl).contrlOwner;
  1297.         
  1298.     // this is where we are declaring the parameters for dragging.
  1299.     slopRect = limitRect = (*cntlWindow).portRect;
  1300.     
  1301.     // now let's determine if we are using a horz or vert control
  1302.     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  1303.     
  1304.         // we have ourselves a horizontal control
  1305.         
  1306.         // adjust the limitRect to take in account where the user clicked whithin the control
  1307.         limitRect.left = cntlRect.left + mousePnt.h;
  1308.         limitRect.right = cntlRect.right - mousePnt.h;
  1309.         
  1310.         // now let's adjust the slopRect slightly, increase it by 20 pixels...
  1311.         InsetRect( &slopRect, -20, -20 );
  1312.         
  1313.         // define our axis that we will use to constrain the indicators movement.
  1314.         axis = noConstraint;
  1315.     
  1316.     } else {
  1317.     
  1318.         // we have a vertical control.
  1319.         
  1320.         // adjust the limitRect to take in account where the user clicked whithin the control
  1321.         limitRect.top = cntlRect.top + mousePnt.v;
  1322.         limitRect.bottom = cntlRect.bottom - mousePnt.v;
  1323.         
  1324.         // now let's adjust the slopRect slightly, increase it by 20 pixels...
  1325.         InsetRect( &slopRect, -20, -20 );
  1326.         
  1327.         // define our axis that we will use to constrain the indicators movement.
  1328.         axis = noConstraint;
  1329.         
  1330.     }
  1331.         
  1332.     // This is the actual routine used to drag the entire control for a more detailed
  1333.     // exlpaination look on page 5-99 IM:Toolbox Essentails or use Think Refrence.
  1334.     DragControl( theControl, mousePnt, &limitRect, &slopRect, axis );
  1335.     
  1336. }
  1337. /******************************************************************************
  1338.  
  1339.     All this procedure does is draw the thumb depending on the current control
  1340.     value. Fairly straight forward procedure. It will get called after the
  1341.     user drags the thumb and if the control recieves a draw entire control msg.
  1342.     
  1343.     I added a simply variable to tell my drawing procedure if I'm drawing for
  1344.     custom dragging or default dragging.  Since I didn't do anything to wild
  1345.     for my dragging I'm using this instead.  If the value is 0 then it just
  1346.     draws the thumb normally. If anything else it draws it with the value in
  1347.     the middle.
  1348.  
  1349. *******************************************************************************/
  1350. void     DrawMyThumb( ControlHandle theControl, Boolean var )
  1351. {
  1352.     Rect            realThumbRect, trackRect;
  1353.     MyCntlDataHan    myData;
  1354.     
  1355.     // set up some variables..
  1356.     myData        = (MyCntlDataHan)(**theControl).contrlData; // force the data to form to our struct
  1357.     
  1358.     // double check to make sure that in fact we have data to play with
  1359.     if( myData != nil ) {
  1360.     
  1361.         // it worked we have data to play with
  1362.         
  1363.         // first draw the track ( to erase any old thumb positions )
  1364.         trackRect = (**myData).trackRect;
  1365.         
  1366.         SetForeColor( GREY_A );
  1367.         PaintRect( &trackRect );
  1368.         
  1369.         //--- add hilites and shadows
  1370.         HiliteAndShadow( GREY_C, WHITE_COLOR, 0, trackRect );
  1371.         FrameRect( &trackRect );
  1372.                         
  1373.         //--- since we now know how large our thumb is, where should we draw it?
  1374.         //--- the position is stored in the control's value field.
  1375.         CalcMyThumbPosition( theControl, &realThumbRect );
  1376.         SetForeColor( GREY_B );
  1377.         PaintRect( &realThumbRect );
  1378.         
  1379.         //--- add hilites and shadows
  1380.         HiliteAndShadow( WHITE_COLOR, GREY_E, 0, realThumbRect );
  1381.         FrameRect( &realThumbRect );
  1382.         
  1383.         if( var != 0 ) {
  1384.             
  1385.             // draw the text in the middle
  1386.             DrawValueInThumb( theControl, (**theControl).contrlValue );
  1387.         
  1388.         }
  1389.         
  1390.     } else {
  1391.     
  1392.         // we couldn't obtain the data for some reason.
  1393.         ReportError( "\pCouldn't access control data while attempting to draw the thumb." );
  1394.         
  1395.     }
  1396. }
  1397.  
  1398. /******************************************************************************
  1399.  
  1400.     All we do here is calculate our thumb rect, convert to a region and copy it
  1401.     into param (which is asking for a region handle) This is done so that the
  1402.     user can drag our thumb.
  1403.  
  1404. *******************************************************************************/
  1405. void    CalcMyThumbRgn( ControlHandle theControl, RgnHandle *param )
  1406. {
  1407.     Rect                realThumbRect;
  1408.         
  1409.     // first let's find the real thumb rect
  1410.     CalcMyThumbPosition( theControl, &realThumbRect );
  1411.     
  1412.     // now just convert it into a rgn (using the pointer to param )
  1413.     RectRgn( *param, &realThumbRect );
  1414. }
  1415.  
  1416. /******************************************************************************
  1417.  
  1418.     Our control was sent a 'posCntl' in the message parameter. param contains the
  1419.     horizontal and vertical offset to move your indicator from it's current
  1420.     position. ( vert = HiWord, horz = LoWord ).
  1421.     
  1422.     We will calculate the new setting and then redraw the control and update
  1423.     it's control value.
  1424.     
  1425.     This one through me for a loop. I wasn't recieving a posCntl for the life of
  1426.     me. I figured out that I wasn't setting the param correctly in FillCntlParameters().
  1427.     I wasn't forcing the data within param to my struct 'CntlParms' correctly. I
  1428.     was forgetting to typeCast the param when sending it to my function.  It's
  1429.     the little things like that that will drive you crazy.
  1430.  
  1431. *******************************************************************************/
  1432. void    PositionMyCntl( ControlHandle theControl, Point mousePnt )
  1433. {
  1434.     short        value;
  1435.  
  1436.     // All we have to do is calculate the new thumb value and then
  1437.     // use CalcMyThumbPosition() to figure out the new location
  1438.     // of the thumb. TrackControl() will handle the draggin if things
  1439.     // are set up correctly in FillCntlParameters().
  1440.     
  1441.     // First convert the point given to us into a new value
  1442.     ConvertPtToVal( theControl, mousePnt, &value );
  1443.     
  1444.     // set the control's value to this new value
  1445.     SetCtlValue( theControl, value );
  1446.     
  1447.     // Now just redraw the indicator or thumb.
  1448.     DrawMyThumb( theControl, 0 );
  1449. }
  1450.  
  1451. /******************************************************************************
  1452.  
  1453.     This procedure will take a point that is within the track Rectangle
  1454.     and convert it to a value.
  1455.  
  1456. *******************************************************************************/
  1457. void     ConvertPtToVal( ControlHandle theControl, Point newPoint, short *value )
  1458. {
  1459.     Rect            trackRect, cntlRect, realThumbRect;
  1460.     short            currThumbCenter, newThumbCenter, trackWidth;
  1461.     long            min, max, newValue;
  1462.     MyCntlDataHan    myData;
  1463.     
  1464.     // extract the control data and form to our struct.
  1465.     myData        = (MyCntlDataHan)(**theControl).contrlData; 
  1466.     
  1467.     // double check to make sure that in fact we have data to play with
  1468.     if( myData != nil ) {
  1469.     
  1470.         // set up some initial variables
  1471.         trackRect = (**myData).trackRect;
  1472.         cntlRect  = (**theControl).contrlRect;
  1473.         min       = (**theControl).contrlMin;
  1474.         max       = (**theControl).contrlMax;
  1475.         
  1476.         if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  1477.         
  1478.             // it's a horizontal control
  1479.             
  1480.             // take in account the thumb length for the edges of the track. I added one
  1481.             // because it had a tendancy to round down and not set my complete value.
  1482.             trackRect.right -= ( MY_THUMB_LENGTH / 2 ) + 1;
  1483.             trackRect.left  += ( MY_THUMB_LENGTH / 2 ) + 1;
  1484.             
  1485.             // we need to obtain the center of the current thumb position
  1486.             CalcMyThumbPosition( theControl, &realThumbRect );
  1487.             currThumbCenter = realThumbRect.left + (( realThumbRect.right - realThumbRect.left ) / 2 );
  1488.             
  1489.             // determine the thumbs new center with the given offset.
  1490.             newThumbCenter = currThumbCenter + newPoint.h;
  1491.             
  1492.             // make sure the point isn't outside the track now that we made adjustments.
  1493.             if( newThumbCenter < trackRect.left ) {
  1494.             
  1495.                 newThumbCenter = trackRect.left;
  1496.                 
  1497.             } else {
  1498.             
  1499.                 if( newThumbCenter > trackRect.right ) { 
  1500.                 
  1501.                     newThumbCenter = trackRect.right;
  1502.                     
  1503.                 }
  1504.             }
  1505.             
  1506.             // find the width of our track rect
  1507.             trackWidth = trackRect.right - trackRect.left;
  1508.             
  1509.             // calculate our new value.
  1510.             newValue = min + ( ( max - min ) * ( newThumbCenter - trackRect.left ) ) / trackWidth;
  1511.             
  1512.         } else {
  1513.         
  1514.             // it's a vertical control
  1515.             
  1516.             // take in account the thumb length for the edges of the track.
  1517.             trackRect.bottom -= ( MY_THUMB_LENGTH / 2 ) + 1;
  1518.             trackRect.top    += ( MY_THUMB_LENGTH / 2 ) + 1;
  1519.             
  1520.             // we need to obtain the center of the current thumb position
  1521.             CalcMyThumbPosition( theControl, &realThumbRect );
  1522.             currThumbCenter = realThumbRect.top + (( realThumbRect.bottom - realThumbRect.top ) / 2 );
  1523.             
  1524.             // determine the thumbs new center with the given offset.
  1525.             newThumbCenter = currThumbCenter + newPoint.v;
  1526.             
  1527.             // make sure the point isn't outside the track now that we made adjustments.
  1528.             if( newThumbCenter < trackRect.top ) {
  1529.             
  1530.                 newPoint.v = trackRect.top;
  1531.                 
  1532.             } else {
  1533.             
  1534.                 if( newThumbCenter > trackRect.bottom ) { 
  1535.                 
  1536.                     newPoint.v = trackRect.bottom;
  1537.                     
  1538.                 }
  1539.             }
  1540.             
  1541.             // find the height of our track rect
  1542.             trackWidth = trackRect.bottom - trackRect.top;
  1543.             
  1544.             // calculate our new value.
  1545.             newValue = min + ( ( max - min ) * ( newThumbCenter - trackRect.top ) ) / trackWidth;
  1546.             
  1547.         }
  1548.         
  1549.         *value = newValue;
  1550.         
  1551.     } else {
  1552.     
  1553.         // We had problems extracting the data from the control's data field
  1554.         ReportError( "\pCouldn't access the control's data while converting a point to a value." );
  1555.         
  1556.     }
  1557. }
  1558.  
  1559. /******************************************************************************
  1560.  
  1561.     Custom Dragging Procedure - not needed if you use default dragging. 
  1562.                                 ( when TrackControl is passed a zero for
  1563.                                   the tracking procedure )
  1564.     
  1565.     Used to draw the controls value within the thumb.
  1566.                                   
  1567.     This is just to show an example of how you could use custom dragging. This
  1568.     is anything to fancy. Will just take the contol's value. Make sure it will
  1569.     fit within our thumb and draw it in its center. For the sake of simplicity
  1570.     we will not do this for a vertical control.
  1571.     
  1572.     In reality you could use this for default draggin also, but I justed wanted
  1573.     to show you something. I'm using a standard drag procedure for my custom
  1574.     dragging so you really don't notice any big difference. This at least shows
  1575.     some difference.
  1576.  
  1577. *******************************************************************************/
  1578. void    DrawValueInThumb( ControlHandle theControl, long value )
  1579. {
  1580.     Rect            realThumbRect, cntlRect;
  1581.     Str15            numString, errString = "\p???";    // will never be greater than 4 digits with our values.
  1582.     short            center, strWidth;                // used to draw our text.
  1583.     GrafPtr            thePort;                        // used to get font info
  1584.     short            txFont, txSize, txFace, txMode;    // to store current font info.
  1585.     RGBColor        theColor;
  1586.     
  1587.     // first it helps to set the cntlRect
  1588.     cntlRect = (**theControl).contrlRect;
  1589.     
  1590.     if( cntlRect.right - cntlRect.left > cntlRect.bottom - cntlRect.top ) {
  1591.         
  1592.         // we have a horizontal control
  1593.         
  1594.         // we do this to find out current font settings.
  1595.         GetPort( &thePort );
  1596.         
  1597.         // Set up some variables and also find & change the current font information
  1598.         NumToString( value, numString );
  1599.         cntlRect = (**theControl).contrlRect;
  1600.         txFont = (*thePort).txFont;
  1601.         txSize = (*thePort).txSize;
  1602.         txFace = (*thePort).txFace;
  1603.         txMode = (*thePort).txMode;
  1604.         GetBackColor( &theColor );
  1605.         TextFont( 9 );
  1606.         TextSize( 9 );
  1607.         TextFace( 0 );
  1608.         TextMode( 0 );     // for this to work and erase the background we need to 
  1609.                         // be sure to set the background color to the thumb color.
  1610.         SetBackColor( GREY_B );        // this is the thumbs color
  1611.         
  1612.         // find the real thumb position
  1613.         CalcMyThumbPosition( theControl, &realThumbRect );
  1614.         
  1615.         // let's double check to make sure our value is bigger than four digits
  1616.         if( numString[0] > 0x04 ) {
  1617.         
  1618.             // we can't have that happen
  1619.             BlockMove( &errString[0], &numString[0], 4 );
  1620.             
  1621.         }
  1622.         
  1623.         center   = realThumbRect.left + (( realThumbRect.right - realThumbRect.left ) / 2 );
  1624.         strWidth = StringWidth( numString );
  1625.         
  1626.         MoveTo( center - ( strWidth / 2 ), realThumbRect.bottom - 4 );
  1627.         DrawString( numString );
  1628.         
  1629.         // redraw hilites and shadows on the thumb because we overWrite them slightly
  1630.         HiliteAndShadow( WHITE_COLOR, GREY_E, 0, realThumbRect );
  1631.         FrameRect( & realThumbRect );
  1632.         
  1633.         // be nice and return everything back to the way they were.
  1634.         TextFont( txFont );
  1635.         TextSize( txSize );
  1636.         TextFace( txFace );
  1637.         TextMode( txMode );
  1638.         RGBBackColor( &theColor );
  1639.         
  1640.     } else {
  1641.     
  1642.         // we have a vertical control so let's not bother
  1643.         
  1644.     }
  1645. }
  1646.  
  1647.  
  1648.  
  1649.  
  1650.  
  1651.